package com.jhw.ymcc.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.jhw.ymcc.domain.Course;
import com.jhw.ymcc.domain.CourseMarket;
import com.jhw.ymcc.domain.KillActivity;
import com.jhw.ymcc.domain.KillCourse;
import com.jhw.ymcc.dto.KillCourseOrderDto;
import com.jhw.ymcc.dto.KillPreOrderParamDto;
import com.jhw.ymcc.exception.GlobalErrorCode;
import com.jhw.ymcc.feign.CourseService;
import com.jhw.ymcc.mapper.KillCourseMapper;
import com.jhw.ymcc.result.JSONResult;
import com.jhw.ymcc.service.IKillActivityService;
import com.jhw.ymcc.service.IKillCourseService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.jhw.ymcc.util.AssertUtil;
import com.jhw.ymcc.util.CodeGenerateUtils;
import com.jhw.ymcc.vo.CourseInfoVo;
import com.jhw.ymcc.vo.CourseOrderVo;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author jhw
 * @since 2022-10-20
 */
@Slf4j
@Service
public class KillCourseServiceImpl extends ServiceImpl<KillCourseMapper, KillCourse> implements IKillCourseService {

    @Autowired
    private CourseService courseService;

    @Autowired
    private IKillActivityService killActivityService;

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired
    private RedissonClient redissonClient;


    @Override
    public boolean insert(KillCourse killCourse) {
        // 判断当前课程是否存在，是是否是上架状态
        JSONResult jsonResult = courseService.get(killCourse.getCourseId());
        Course course = JSONObject.parseObject(JSON.toJSONString(jsonResult.getData()), Course.class);
        AssertUtil.isNotNull(course, GlobalErrorCode.ERROR);
        boolean boo = course.getStatus() == Course.STATUS_ON_LINE;
        AssertUtil.isTrue(boo, GlobalErrorCode.ERROR);
        // 判断此课程是否已经加入秒杀课程、没有才可以加入
        KillCourse killCourseTemp = selectCourseBykillCourseIdAndKillActivityId(killCourse.getActivityId(), killCourse.getCourseId());
        AssertUtil.isNull(killCourseTemp, GlobalErrorCode.ERROR);
        // 活动状态必须是待发布才可以加入
        KillActivity killActivity = killActivityService.selectById(killCourse.getActivityId());
        AssertUtil.isNotNull(killActivity, GlobalErrorCode.ERROR);
        boolean isOk = killActivity.getPublishStatus() == killActivity.STATUS_WAIT_PUBLISH;
        AssertUtil.isTrue(isOk, GlobalErrorCode.ERROR);
        // 设置前端未传递的值
        killCourse.setCreateTime(new Date());
        killCourse.setTimeStr(killActivity.getTimeStr());
        killCourse.setTeacherNames(course.getTeacherNames());
        killCourse.setStartTime(killActivity.getBeginTime());
        killCourse.setEndTime(killActivity.getEndTime());
        killCourse.setPublishStatus(killActivity.getPublishStatus());
        return super.insert(killCourse);
    }


    /**
     * 根据活动id和课程id查询是否是否存在这个课程
     * @param activityId
     * @param courseId
     * @return
     */
    private KillCourse selectCourseBykillCourseIdAndKillActivityId(Long activityId, Long courseId) {
        Wrapper<KillCourse> wrapper = new EntityWrapper<>();
        wrapper.eq("course_id", courseId);
        wrapper.eq("activity_id", activityId);
        return selectOne(wrapper);
    }

    @Override
    public List<KillCourse> onlineAll() {
        List<KillCourse> killCourses = new ArrayList<>();
        Set<Object> keys = redisTemplate.keys("actity6");
        keys.forEach(key ->{
            // values：根据大key直接拿到对应的小value
            List values = redisTemplate.opsForHash().values(key);
            killCourses.addAll(values);
        });
        return killCourses;
    }

    @Override
    public KillCourse onlineOne(Long killActivityId, Long killCourseId) {
        return (KillCourse) redisTemplate.opsForHash().get("actity" + killActivityId, killCourseId.toString());
    }

    @Override
    public String kill(KillCourseOrderDto killCourseOrderDto) {
        Date now = new Date();
        Long userId = 3L;
        // 判断redsi中是否有这个课程
        Object killCourseTemp = redisTemplate.opsForHash().get("actity" + killCourseOrderDto.getKillActivityId(), killCourseOrderDto.getKillCourseId().toString());
        AssertUtil.isNotNull(killCourseTemp, GlobalErrorCode.ERROR);
        // 判断课程是否正在秒杀中
        KillCourse killCourse = JSON.parseObject(JSON.toJSONString(killCourseTemp), KillCourse.class);
        AssertUtil.isTrue(killCourse.getKilling(), GlobalErrorCode.ERROR);
        // 扣减信号量
        RSemaphore semaphore = redissonClient.getSemaphore(killCourseOrderDto.getKillActivityId() + ":" + killCourseOrderDto.getKillCourseId());
        boolean b = semaphore.tryAcquire(1);
        // 秒杀失败就抛出一个异常
        AssertUtil.isTrue(b, GlobalErrorCode.ERROR);
        // 创建预创订单
        KillPreOrderParamDto killPreOrderParamDto = new KillPreOrderParamDto();
        killPreOrderParamDto.setCourseId(killCourse.getId());
        killPreOrderParamDto.setKillCourseId(killCourse.getCourseId());
        killPreOrderParamDto.setCoursePic(killCourse.getCoursePic());
        killPreOrderParamDto.setKillActivityId(killCourse.getActivityId());
        killPreOrderParamDto.setCourseName(killCourse.getCourseName());
        killPreOrderParamDto.setTotalCount(1);
        killPreOrderParamDto.setTotalAmount(killCourse.getKillPrice());
        String orderNo = CodeGenerateUtils.generateOrderSn(userId);
        killPreOrderParamDto.setOrderNo(orderNo);
        killPreOrderParamDto.setUserId(userId);
        // 将预存订单存入redis
        redisTemplate.opsForValue().set(orderNo, killPreOrderParamDto);
        // 秒杀耗时
        log.info("秒杀耗时：{}", System.currentTimeMillis() - now.getTime());
        return orderNo;
    }

    @Override
    public CourseInfoVo killOnline(String orderNo) {
        Object o = redisTemplate.opsForValue().get(orderNo);
        AssertUtil.isNotNull(o, GlobalErrorCode.ERROR);
        KillPreOrderParamDto killPreOrderParamDto = JSON.parseObject(JSON.toJSONString(o), KillPreOrderParamDto.class);


        CourseInfoVo courseInfoVo = new CourseInfoVo();
        List<CourseOrderVo> courseOrderVos = new ArrayList<>();

        // 3.遍历所有课程封装返回值
        CourseOrderVo courseOrderVo = new CourseOrderVo();

        Course course = new Course();
        course.setName(killPreOrderParamDto.getCourseName());
        course.setPic(killPreOrderParamDto.getCoursePic());
        CourseMarket courseMarket = new CourseMarket();
        courseMarket.setPrice(killPreOrderParamDto.getTotalAmount());

        courseOrderVo.setCourse(course);
        courseOrderVo.setCourseMarket(courseMarket);

        courseInfoVo.setTotalAmount(killPreOrderParamDto.getTotalAmount());

        courseOrderVos.add(courseOrderVo);
        courseInfoVo.setCourseInfoVos(courseOrderVos);

        return courseInfoVo;
    }
}
